package com.xuanmiao.smsback.service.statement;

import com.panshi.hujin2.base.common.util.DoubleUtils;
import com.panshi.hujin2.base.domain.page.Page;
import com.xuanmiao.smsback.dao.mapper.ExpenseCalendarMapper;
import com.xuanmiao.smsback.dao.mapper.UserInfoMapper;
import com.xuanmiao.smsback.dao.mapper.sms.MessageSendRecordMapper;
import com.xuanmiao.smsback.dao.mapper.sms.MsgSendManageMapper;
import com.xuanmiao.smsback.dao.model.ExpenseCalendarDO;
import com.xuanmiao.smsback.dao.model.UserInfoDO;
import com.xuanmiao.smsback.dao.model.sms.MessageSendRecordDO;
import com.xuanmiao.smsback.dao.model.sms.MsgSendManageDO;
import com.xuanmiao.smsback.domain.qo.MessageSendManageQO;
import com.xuanmiao.smsback.domain.qo.MessageSendRecordQO;
import com.xuanmiao.smsback.service.statement.bo.*;
import com.xuanmiao.smsback.service.statement.qo.BaseTimeQO;
import com.xuanmiao.smsback.service.statement.qo.ConsumeRecordStatementQO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 消费报表
 */
@Service
@Slf4j
public class ConsumeStatementServiceImpl implements ConsumeStatementService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private MessageSendRecordMapper messageSendRecordMapper;

    @Autowired
    private MsgSendManageMapper msgSendManageMapper;

    @Autowired
    ExpenseCalendarMapper expenseCalendarMapper;
    
    

    /**
     * 报表-消费排行
     * @param qo
     * @return
     */
    @Override
    public List<ConsumeRankStatementBO> getRank(BaseTimeQO qo) {

        List<ConsumeRankStatementBO> resList = new ArrayList<>();
        List<UserInfoDO> userInfos = userInfoMapper.selectAll();
        Map<String, List<UserInfoDO>> userMap = new HashMap<>();
        if (CollectionUtils.isEmpty(userInfos)) {
            return Collections.emptyList();
        }
        userInfos.stream().forEach(userInfo -> {
            String businessNo = userInfo.getBusinessNo();
            List<UserInfoDO> list = userMap.get(businessNo);
            if (list == null) {
                list = new ArrayList<>();
            }
            list.add(userInfo);
            userMap.put(businessNo, list);
        });
        Set<String> keySet = userMap.keySet();
        Iterator<String> it = keySet.iterator();
        while (it.hasNext()) {
            String key = it.next();
            List<UserInfoDO> list = userMap.get(key);
            ConsumeRankStatementBO consumeStatementBO = new ConsumeRankStatementBO();
            consumeStatementBO.setBusinessNo(key);
            List<UserInfoDO> userList = list.stream().filter(userInfoDO -> {
                return userInfoDO.getIsMain();
            }).collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(userList)){
                UserInfoDO mainUser =userList.get(0);
                consumeStatementBO.setCompany(mainUser.getCompanyName());
                consumeStatementBO.setUserId(mainUser.getId());
                consumeStatementBO.setConsumerId(mainUser.getId());
                resList.add(consumeStatementBO);
            }
        }

        resList.stream().forEach(consumeStatementBO -> {
            String businessNo = consumeStatementBO.getBusinessNo();
            List<UserInfoDO> list = userMap.get(businessNo);
            List<Double> amountList = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(userInfoDO -> {
                    MessageSendManageQO messageSendManageQO = new MessageSendManageQO();
                    Page page = new Page();page.setIsPaging(false);
                    messageSendManageQO.setPage(page);
                    messageSendManageQO.setCreateTimeEnd(qo.getEnd());
                    messageSendManageQO.setCreateTimeStart(qo.getStart());
                    messageSendManageQO.setConsumerId(userInfoDO.getId());
                    List<MsgSendManageDO> messageSendManageList = msgSendManageMapper.queryByQO(messageSendManageQO);
                    if (CollectionUtils.isNotEmpty(messageSendManageList)) {
                        messageSendManageList.stream().forEach(msgSendManageDO -> {
                            // 失效或者:1-发送中；2-等待；3-暂停；不做统计
                            if(msgSendManageDO.getStatus() == 0){
                                return ;
                            }
                            Integer sendStatus = msgSendManageDO.getSendStatus();
                            if(sendStatus == 1 || sendStatus == 2 || sendStatus == 3){
                                return ;
                            }
                            Double singleFee = msgSendManageDO.getSingleFee();
                            MessageSendRecordQO messageSendRecordQO = new MessageSendRecordQO();
                            messageSendRecordQO.setQueueId(msgSendManageDO.getId());
                            List<MessageSendRecordDO> smsRecordList = messageSendRecordMapper.queryByQO(messageSendRecordQO);
                            long smsSuccessCount = smsRecordList.stream().filter(messageSendRecordDO -> {
                                return messageSendRecordDO.getResCode().equals(0);
                            }).count();
                            amountList.add(DoubleUtils.multiply((double) smsSuccessCount, singleFee));
                        });
                    }
                });
            }
            Double amount = amountList.stream().mapToDouble(o -> {
                return o;
            }).sum();
            consumeStatementBO.setAmount(amount);
        });

        resList.sort((o1,o2)->{
            return o2.getAmount().compareTo(o1.getAmount());
        });

        for(int i=0;i<resList.size();i++){
            resList.get(i).setOrder(i+1);
        }
        return resList;
    }

    /**
     * 报表-消费趋势
     * @param qo
     * @return
     */
    @Override
    public ConsumeTrendStatementBO getTrend(BaseTimeQO qo) {

        ConsumeTrendStatementBO consumeTrendStatementBO = new ConsumeTrendStatementBO();
        consumeTrendStatementBO.setAmount(0.0);
        consumeTrendStatementBO.setSmsCount(0);
        consumeTrendStatementBO.setSmsFailedCount(0);
        consumeTrendStatementBO.setSmsSuccessCount(0);
        consumeTrendStatementBO.setDetails(Collections.EMPTY_LIST);
        consumeTrendStatementBO.setSmsCountDetails(Collections.EMPTY_LIST);
        consumeTrendStatementBO.setSmsSuccessCountDetails(Collections.EMPTY_LIST);
        consumeTrendStatementBO.setSmsFailedCountDetails(Collections.EMPTY_LIST);

        // 消费
        MessageSendManageQO messageSendManageQO = new MessageSendManageQO();
        messageSendManageQO.setCreateTimeEnd(qo.getEnd());
        messageSendManageQO.setCreateTimeStart(qo.getStart());
        Page page = new Page();page.setIsPaging(false);
        messageSendManageQO.setPage(page);
        messageSendManageQO.setSendStatusList(Stream.of(4,5,6).collect(Collectors.toList()));
        List<MsgSendManageDO> messageSendManageList = msgSendManageMapper.queryByQO(messageSendManageQO);

        Map<String, List<MsgSendManageDO>> msgSendManageMap = new HashMap<>();
        Map<String, List<ExpenseCalendarDO>> expenseMap = new HashMap<>();
        // 初始化map
        LocalDateTime start = LocalDateTime.ofInstant(qo.getStart().toInstant(), ZoneId.systemDefault());
        LocalDateTime end = LocalDateTime.ofInstant(qo.getEnd().toInstant(), ZoneId.systemDefault());
        while(start.isBefore(end)){
            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd");
            String timeStr = start.format(dtf);
            msgSendManageMap.put(timeStr,new ArrayList<>());
            expenseMap.put(timeStr,new ArrayList<>());
            start = start.plusDays(1);
        }
        if (CollectionUtils.isEmpty(messageSendManageList)) {
            return consumeTrendStatementBO;
        }
        messageSendManageList.stream().forEach(msgSendManageDO -> {
            Date createTime = msgSendManageDO.getCreateTime();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
            String createTimeStr = sdf.format(createTime);
            List<MsgSendManageDO> list = msgSendManageMap.get(createTimeStr);
            if (list == null) {
                list = new ArrayList<>();
            }
            list.add(msgSendManageDO);
            msgSendManageMap.put(createTimeStr, list);
        });

        Set<String> keySet = msgSendManageMap.keySet();
        Iterator<String> it = keySet.iterator();
        List<ConsumeTrendDetailStatementBO> details = new ArrayList<>();
        List<Integer> successCountList = new ArrayList<>();
        List<Integer> failedCountList = new ArrayList<>();
        List<Integer> totalCountList = new ArrayList<>();
        List<Double> totalAmountList = new ArrayList<>();
        while (it.hasNext()) {
            String key = it.next();
            ConsumeTrendDetailStatementBO consumeTrendDetailStatementBO = new ConsumeTrendDetailStatementBO();
            consumeTrendDetailStatementBO.setDate(key);
            consumeTrendDetailStatementBO.setAmount(0.0);
            List<MsgSendManageDO> list = msgSendManageMap.get(key);
            if (CollectionUtils.isNotEmpty(list)) {
                List<Double> amountList = new ArrayList<>();
                list.stream().forEach(msgSendManageDO -> {
                    // 失效或者:1-发送中；2-等待；3-暂停；不做统计
                    if(msgSendManageDO.getStatus() == 0){
                        return ;
                    }
                    Integer sendStatus = msgSendManageDO.getSendStatus();
                    if(sendStatus == 1 || sendStatus == 2 || sendStatus == 3){
                        return ;
                    }
                    Double singleFee = msgSendManageDO.getSingleFee();
                    MessageSendRecordQO messageSendRecordQO = new MessageSendRecordQO();
                    messageSendRecordQO.setQueueId(msgSendManageDO.getId());
                    List<MessageSendRecordDO> smsRecordList = messageSendRecordMapper.queryByQO(messageSendRecordQO);
                    long smsSuccessCount = smsRecordList.stream().filter(messageSendRecordDO -> {
                        return messageSendRecordDO.getResCode().equals(0);
                    }).count();
                    successCountList.add((int) smsSuccessCount);
                    failedCountList.add((int) (msgSendManageDO.getCount() - smsSuccessCount));
                    amountList.add(DoubleUtils.multiply((double) smsSuccessCount, singleFee));
                    totalCountList.add(msgSendManageDO.getCount());
                    totalAmountList.add(DoubleUtils.multiply((double) smsSuccessCount, singleFee));
                });
                Double amount = amountList.stream().mapToDouble(o -> {
                    return o;
                }).sum();
                consumeTrendDetailStatementBO.setAmount(amount);
            }
            details.add(consumeTrendDetailStatementBO);
        }
        consumeTrendStatementBO.setDetails(details);
        int successCount = successCountList.stream().mapToInt(o -> {
            return o;
        }).sum();
        int failedCount = failedCountList.stream().mapToInt(o -> {
            return o;
        }).sum();

        Double amountTotal = totalAmountList.stream().mapToDouble(o -> {
            return o;
        }).sum();

        int countTotal = totalCountList.stream().mapToInt(o -> {
            return o;
        }).sum();


        consumeTrendStatementBO.setAmount(amountTotal);
        consumeTrendStatementBO.setSmsCount(countTotal);
        consumeTrendStatementBO.setSmsFailedCount(failedCount);
        consumeTrendStatementBO.setSmsSuccessCount(successCount);


        List<ExpenseCalendarDO> expenselist = expenseCalendarMapper.query(qo.getStart(), qo.getEnd());
        if(CollectionUtils.isNotEmpty(expenselist)){

            expenselist.stream().forEach(expenseCalendar -> {
                Date endTime = expenseCalendar.getEndTime();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
                String endTimeStr = sdf.format(endTime);
                List<ExpenseCalendarDO> list = expenseMap.get(endTimeStr);
                if (list == null) {
                    list = new ArrayList<>();
                }
                list.add(expenseCalendar);
                expenseMap.put(endTimeStr, list);
            });
            Set<String> keySet1 = expenseMap.keySet();
            Iterator<String> it1 = keySet1.iterator();
            List<SmsCountTrendDetailStatementBO> smsCountList = new ArrayList<>();
            List<SmsCountTrendDetailStatementBO> smsFailedCountList = new ArrayList<>();
            List<SmsCountTrendDetailStatementBO> smsSuccessCountList = new ArrayList<>();

            while (it1.hasNext()) {
                String key = it1.next();

                List<ExpenseCalendarDO> list = expenseMap.get(key);
                MsgCount msgCount = new MsgCount();
                if (CollectionUtils.isNotEmpty(list)) {
                    list.stream().forEach(expenseCalendarDO -> {
                        msgCount.smsCount+=expenseCalendarDO.getSendNumber();
                        msgCount.smsFailedCount+=expenseCalendarDO.getSendFailNumber();
                        msgCount.smsSuccessCount+=expenseCalendarDO.getSendSuccessNumber();
                    });
                }
                smsCountList.add(new SmsCountTrendDetailStatementBO(key,msgCount.smsCount));
                smsFailedCountList.add(new SmsCountTrendDetailStatementBO(key,msgCount.smsFailedCount));
                smsSuccessCountList.add(new SmsCountTrendDetailStatementBO(key,msgCount.smsSuccessCount));
            }
            consumeTrendStatementBO.setSmsSuccessCountDetails(smsSuccessCountList);
            consumeTrendStatementBO.setSmsFailedCountDetails(smsFailedCountList);
            consumeTrendStatementBO.setSmsCountDetails(smsCountList);
        }

        return consumeTrendStatementBO;
    }

    /**
     * 报表-消费记录
     * @param qo
     * @return
     */
    @Override
    public List<ConsumeRecordStatementBO> getRecord(ConsumeRecordStatementQO qo) {

        MessageSendManageQO messageSendManageQO = new MessageSendManageQO();
        messageSendManageQO.setConsumerCode(qo.getQueueId());
        messageSendManageQO.setCreateTimeStart(qo.getCreateTimeStart());
        messageSendManageQO.setCreateTimeEnd(qo.getCreateTimeEnd());
        messageSendManageQO.setConsumerId(qo.getConsumerId());
        messageSendManageQO.setSendStatus(qo.getSendStatus());
        messageSendManageQO.setPage(qo.getPage());
        messageSendManageQO.setSendStatusList(Stream.of(4,5,6).collect(Collectors.toList()));
        int count = msgSendManageMapper.countByQO(messageSendManageQO);
        if(count>0){
            Page page = messageSendManageQO.getPage();
            page.setTotalNumber(count);
            List<MsgSendManageDO> list = msgSendManageMapper.queryByQO(messageSendManageQO);
            List<ConsumeRecordStatementBO> returnList = new ArrayList<>();
            list.stream().forEach(msgSendManageDO->{
                // 失效或者:1-发送中；2-等待；3-暂停；不做统计
                if(msgSendManageDO.getStatus() == 0){
                    return ;
                }
                Integer sendStatus = msgSendManageDO.getSendStatus();
                if(sendStatus == 1 || sendStatus == 2 || sendStatus == 3){
                    return ;
                }
                ConsumeRecordStatementBO consumeRecordStatementBO = new ConsumeRecordStatementBO();
                consumeRecordStatementBO.setConsumerCode(msgSendManageDO.getConsumerCode());
                consumeRecordStatementBO.setConsumerId(msgSendManageDO.getConsumerId());
                // 实际发送人账户
                Integer realSenderId = msgSendManageDO.getCurrentConsumerId();
                UserInfoDO realSender = userInfoMapper.getById(realSenderId);
                consumeRecordStatementBO.setRealAccountNo(realSender.getAccountNo());

                consumeRecordStatementBO.setUserId(msgSendManageDO.getConsumerId());
                consumeRecordStatementBO.setQueueId(msgSendManageDO.getId());
                consumeRecordStatementBO.setCreateTime(msgSendManageDO.getCreateTime());
                consumeRecordStatementBO.setSendTime(msgSendManageDO.getSendTime());
                // TODO 结束时间
                Date stopDate = messageSendRecordMapper.selectLastDate(msgSendManageDO.getId());
                consumeRecordStatementBO.setEndTime(stopDate);
                consumeRecordStatementBO.setStatus(msgSendManageDO.getSendStatus());

                // 发送条数
                MessageSendRecordQO messageSendRecordQO = new MessageSendRecordQO();
                messageSendRecordQO.setQueueId(msgSendManageDO.getId());
                List<MessageSendRecordDO> smsRecordList = messageSendRecordMapper.queryByQO(messageSendRecordQO);
                if(CollectionUtils.isNotEmpty(smsRecordList)){
                    consumeRecordStatementBO.setSmsCount(smsRecordList.size());// 发送条数
                    int successCount = (int) smsRecordList.stream().filter(o -> {
                        return o.getResCode().equals(0);
                    }).count();
                    consumeRecordStatementBO.setSmsTakeCount(successCount);
                    consumeRecordStatementBO.setSmsSuccessCount(successCount);// 成功条数
                    consumeRecordStatementBO.setSmsFailedCount(smsRecordList.size() - successCount);// 失败号码
                    consumeRecordStatementBO.setAmount(msgSendManageDO.getSingleFee() * successCount);
                }
                returnList.add(consumeRecordStatementBO);
            });

            return returnList;
        }

        return Collections.emptyList();
    }


    class MsgCount{

        int smsCount = 0;

        int smsSuccessCount = 0;

        int smsFailedCount = 0;
    }
}
